import router from './index'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { Message } from 'element-ui'
import VueRouter, { Route, RouteConfig, NavigationGuardNext, RawLocation } from 'vue-router'
import { UserModule } from '@/store/modules/user'
import { PermissionModule } from '@/store/modules/permission'

// fix Error: Redirected when going from “/login“ to “/home“ via a navigation guard.
const VueRouterReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function replace (location: RawLocation): any {
  return VueRouterReplace.call<any, any, any>(this, location).catch((err: Error) => err)
}
NProgress.configure({ showSpinner: false })
const whiteList = ['/login']

// https://www.cnblogs.com/nirvanan/articles/14338825.html
// https://cloud.tencent.com/developer/article/1579496?from=information.detail.next({%20...to,%20replace:%20true%20})%E6%AD%BB%E5%BE%AA%E7%8E%AF
router.beforeEach(async (to: Route, from: Route, next: NavigationGuardNext) => {
  NProgress.start()

  if (UserModule.token) { // 如果用户已登录就不能访问登录界面，需要中断这一次路由守卫，执行下一次路由守卫，并且下一次守卫的to应该是首页
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      if (UserModule.roles.length === 0) { // 如果用户的角色数组为空，那么去请求后台接口获取用户的角色，通过用户角色生成对应的路由表
        try {
          await UserModule.GetUserInfo() // 请求后台接口获取用户信息包括角色
          const roles = UserModule.roles

          const accessedRoutes: RouteConfig[] = await PermissionModule.GenerateRoutes(roles) // 拿到用户角色生成对应的路由表

          // Dynamically add accessible routes
          router.addRoutes(accessedRoutes)

          // 在addRoutes()之后第一次访问被添加的路由会白屏，这是因为刚刚addRoutes()就立刻访问被添加的路由，然而此时addRoutes()没有执行结束，因而找不到刚刚被添加的路由导致白屏。因此需要从新访问一次路由才行
          // 确保addRoutes()时动态添加的路由已经被完全加载上去，如果addRoutes并未完成，路由守卫会一层一层的执行执行，直到addRoutes完成并且to有值，才放行
          next({ ...to, replace: true } as any)
          // replace模式访问/xxx 路由，这种模式用户在登录之后不会在 history存放记录
        } catch (err) {
          // 清空用户登录信息重新登录
          UserModule.LogoutSubmit()
          Message.error(err || '请求错误，请重新登录')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      } else {
        next()
      }
    }
  } else {
    // 用户未登录:(1)用户去的路由存在于白名单内，直接通过；(2)用户去的路由不存在于白名单内，需要重定向
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
  next()
})

router.afterEach((to: Route) => {
  NProgress.done()
  document.title = to.meta.title
})
